#include "multitasker.h"
#include "in_out.h"
#include "../driver/keyboard.h"
#include "../driver/screen.h"

#include "klib/buffer.h"
#include "filesystem.h"
#include "isr.h"



void tty_func(tty_t* tty){
	if(tty==NULL){
		return;
	}
	int tmp1;
	int tmp2;
	
	buffer_t * buff_in=&keyboard_buffer;
	buffer_t * buff_out1=tty->inner_buffer;
	buffer_t * buff_out2=tty->stdout;
	
	/*
	Saco por pantalla lo que entro por teclado, y tambien lo mando a un buffer interno, para que
	cuando se flushee se lo mande al stdin.
	*/
	tmp1=(buff_out1->end+1)%BUFFER_SIZE;
	tmp2=(buff_out2->end+1)%BUFFER_SIZE;
	while(tmp2!=buff_out2->start && tmp1!=buff_out1->start && buff_in->start!=buff_in->end){
	
		/*
		Si viene un enter, es hora de flushear.
		*/
		if(buff_in->array[buff_in->start]=='\n')
			tty->flush=1;
		

		if(buff_in->array[buff_in->start]!='\b'){
		
			/*
			Paso el caracter al stdout.
			*/
			buff_out2->array[buff_out2->end]=buff_in->array[buff_in->start];
			buff_out2->end=tmp2;
			tmp2=(buff_out2->end+1)%BUFFER_SIZE;
		
			/*
			Si lo que vino de teclado no es un backspace, lo paso al buffer interno.
			*/
			buff_out1->array[buff_out1->end]=buff_in->array[buff_in->start];
			buff_out1->end=tmp1;
		
		} 
		else if(buff_out1->start!=buff_out1->end){
			
			/*
			Paso el caracter al stdout.
			*/
			buff_out2->array[buff_out2->end]=buff_in->array[buff_in->start];
			buff_out2->end=tmp2;
			tmp2=(buff_out2->end+1)%BUFFER_SIZE;
		
			/*
			Si lo que vino de teclado es un backspace, saco lo ultimo que habia puesto en
			el buffer interno (solo si habia algo).
			*/
			buff_out1->end=(BUFFER_SIZE+buff_out1->end-1)%BUFFER_SIZE;
		
		}
		
		
		tmp1=(buff_out1->end+1)%BUFFER_SIZE;
		buff_in->start=(buff_in->start+1)%BUFFER_SIZE;
	}
	

	if(tty->flush || (tty->inner_buffer->end+1)%BUFFER_SIZE == tty->inner_buffer->start){
		/*
		Copio todo el buffer interno al stdin.
		*/
		flush_buffer_into_buffer(tty->stdin, tty->inner_buffer);
		tty->flush=0;
		/*
		Desbloqueo a todos los que estaban esperando en el stdin.
		*/
		unblock_all_from_when(&tty->stdin->block_list,Blocked_read);
	}
	
	/*
	Escrivo en pantalla todo lo que estaba en el stdout.
	*/
	int i;
	for (i = 0; tty->stdout->start != tty->stdout->end; i++) {
		screen_put(tty->stdout->array[tty->stdout->start]);
		tty->stdout->start = (tty->stdout->start + 1) % BUFFER_SIZE;
	}

	/*
	Desbloqueo a todos los que estaban esperando en el stdout.
	*/
	unblock_all_from_when(&tty->stdout->block_list,Blocked_write);
}


uint32_t sys_newstdio(registers_t* regs){
	tty_t* tty=get_tty();
	
	tty->flush=0;
	
	int fd0=get_free_in_out(-1, FIFO_TYPE, READ_PERMISSION);
	int fd1=get_free_in_out(-1, FIFO_TYPE, WRITE_PERMISSION);
	
	get_buffer(get_free_in_out(-1,FIFO_TYPE),&tty->inner_buffer);
	
	set_fd2(0,fd0);
	get_buffer(fd0,&tty->stdin);
	
	set_fd2(1,fd1);
  	get_buffer(fd1,&tty->stdout);
	
	
	return 0;
}

void init_tty(){
	register_functionality(52,sys_newstdio);
}
